package com.google.android.apps.wakemewhere.mapsearch;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.android.maps.GeoPoint;

import android.content.Context;
import android.location.Address;
import android.location.Geocoder;

public class PlaceSearch implements SearchResultProvider {

	private static final Logger logger = Logger.getLogger(PlaceSearch.class.getName());

	private static final int MAX_RESULTS = 10;
	private static final int RESULT_PRIORITY = 5;
	
	private final Geocoder geocoder;
	private final Executor executor = Executors.newSingleThreadExecutor();
	
	PlaceSearch(Context context) {
		geocoder = new Geocoder(context);
	}
	
	public void asyncSearch(String query, SearchResultCallback callback, Object tag, GeoPoint mapLowerLeft, GeoPoint mapUpperRight) {
		executor.execute(new GeocodeRunnable(query, callback, tag, mapLowerLeft, mapUpperRight));
	}

	public class GeocodeRunnable implements Runnable {
		private final String locationName;
		private final SearchResultCallback callback;
		private final Object tag;
		
		GeocodeRunnable(String locationName, SearchResultCallback callback, Object tag, GeoPoint mapLowerLeft, GeoPoint mapUpperRight) {
			this.locationName = locationName;
			this.callback = callback;
			this.tag = tag;
		}
		
		public void run() {
			try {
				logger.log(Level.FINE, "Starting location search");
				List<Address> response = geocoder.getFromLocationName(locationName, MAX_RESULTS);
				logger.log(Level.FINE, "Location search complete - executing callback");
				logger.warning("*** RESULTS ARE IN.  THERE ARE " + response.size());
				callback.onSearchResults(asSearchResults(response), tag, PlaceSearch.this, true);
				logger.log(Level.FINE, "Callback finished");
			} catch (Throwable t) {
				logger.log(Level.WARNING, "Unable to get results from geocoder", t);
			}
		}
	}
	
	private static List<SearchResult> asSearchResults(List<Address> response) {
		List<SearchResult> results = new ArrayList<SearchResult>();
		for (Address address : response) {
			results.add(new SearchResult(name(address), address(address), RESULT_PRIORITY, geopoint(address)));
		}
		return results;
	}
	
	private static String name(Address address) {
		String name = address.getAddressLine(0);
		if (name == null) {
			name = "";
		}
		return name;
	}
	
	private static String address(Address address) {
		String out = "";
		int i = 1;
		String result = address.getAddressLine(i);
		while (result != null) {
			if (out.length() > 0) {
				out += ", ";
			}
			out += result;
			i++;
			result = address.getAddressLine(i);
		}
		return out;
	}
	
	private static GeoPoint geopoint(Address address) {
		logger.info("Geopoint extracted from place: " + address.getLatitude() + " " + address.getLongitude());
		return new GeoPoint((int)(address.getLatitude() * 1E6d), (int)(address.getLongitude() * 1E6d));
	}
}
